
/*
 * Copyright (C) 2008-2009 Archie L. Cobbs. All rights reserved.
 *
 * $Id: IndexTest2.java 377 2010-03-11 20:50:18Z archie.cobbs $
 */

package org.dellroad.sidekar;

import java.util.Arrays;
import java.util.List;

import org.dellroad.sidekar.annotation.SidekarEntity;
import org.dellroad.sidekar.annotation.SidekarField;
import org.dellroad.sidekar.annotation.SidekarIndex;
import org.dellroad.sidekar.util.VoidDatabaseAction;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;

/**
 * Verify proper sorting of indexes on the various field types.
 */
public class IndexTest2 extends DatabaseTest {

    @Test
    public void testIndex1() {

        // Populate
        this.db.performTransaction(null, new VoidDatabaseAction() {
            public void executeVoid() {
                checkSorting();
            }
        });
    }

    protected void checkSorting() {

        // Create objects
        Entity<Prim> entity = this.db.getEntity(Prim.class);
        Prim[] prims = new Prim[8];
        for (int i = 0; i < prims.length; i++)
            prims[i] = entity.create();

        // Randomly set fields, then check sorting
        for (int i = 0; i < 100; i++) {

            // Change one field in each object
            for (int j = 0; j < prims.length; j++) {
                final Prim prim = prims[j];
                switch (this.random.nextInt(8)) {
                case 0:
                    prim.setZ(this.random.nextBoolean());
                    break;
                case 1:
                    byte[] buf = new byte[1];
                    this.random.nextBytes(buf);
                    prim.setB(buf[0]);
                    break;
                case 2:
                    prim.setC((char)this.random.nextInt());
                    break;
                case 3:
                    prim.setS((short)this.random.nextInt());
                    break;
                case 4:
                    prim.setI(this.random.nextInt());
                    break;
                case 5:
                    prim.setF((float)(this.random.nextDouble() * 2e6 - 1e6));
                    break;
                case 6:
                    prim.setJ(this.random.nextLong());
                    break;
                case 7:
                    prim.setD(this.random.nextDouble() * 2e6 - 1e6);
                    break;
                default:
                    throw new RuntimeException();
                }
            }

            // Verify proper index sorts
            Prim prev = null;
            for (Prim prim : entity.getIndex("z")) {
                if (prev != null)
                    checkSort(prev.getZ(), prim.getZ());
                prev = prim;
            }
            prev = null;
            for (Prim prim : entity.getIndex("b")) {
                if (prev != null)
                    checkSort(prev.getB(), prim.getB());
                prev = prim;
            }
            prev = null;
            for (Prim prim : entity.getIndex("c")) {
                if (prev != null)
                    checkSort(prev.getC(), prim.getC());
                prev = prim;
            }
            prev = null;
            for (Prim prim : entity.getIndex("s")) {
                if (prev != null)
                    checkSort(prev.getS(), prim.getS());
                prev = prim;
            }
            prev = null;
            for (Prim prim : entity.getIndex("i")) {
                if (prev != null)
                    checkSort(prev.getI(), prim.getI());
                prev = prim;
            }
            prev = null;
            for (Prim prim : entity.getIndex("f")) {
                if (prev != null)
                    checkSort(prev.getF(), prim.getF());
                prev = prim;
            }
            prev = null;
            for (Prim prim : entity.getIndex("j")) {
                if (prev != null)
                    checkSort(prev.getJ(), prim.getJ());
                prev = prim;
            }
            prev = null;
            for (Prim prim : entity.getIndex("d")) {
                if (prev != null)
                    checkSort(prev.getD(), prim.getD());
                prev = prim;
            }
        }
    }

    private <T extends Comparable<T>> void checkSort(T x, T y) {
        assertTrue(x.compareTo(y) <= 0, x + " is greater than " + y);
    }

    @Override
    protected List<Class<?>> getSchemaClasses() {
        return Arrays.<Class<?>>asList(Prim.class);
    }

    // Model classes

    @SidekarEntity(indexes = {
      @SidekarIndex(name = "z", fields = "z"),
      @SidekarIndex(name = "b", fields = "b"),
      @SidekarIndex(name = "c", fields = "c"),
      @SidekarIndex(name = "s", fields = "s"),
      @SidekarIndex(name = "i", fields = "i"),
      @SidekarIndex(name = "f", fields = "f"),
      @SidekarIndex(name = "j", fields = "j"),
      @SidekarIndex(name = "d", fields = "d")
    })
    public abstract static class Prim implements Item {

        @SidekarField
        public abstract boolean getZ();
        public abstract void setZ(boolean value);

        @SidekarField
        public abstract byte getB();
        public abstract void setB(byte value);

        @SidekarField
        public abstract char getC();
        public abstract void setC(char value);

        @SidekarField
        public abstract short getS();
        public abstract void setS(short value);

        @SidekarField
        public abstract int getI();
        public abstract void setI(int value);

        @SidekarField
        public abstract float getF();
        public abstract void setF(float value);

        @SidekarField
        public abstract long getJ();
        public abstract void setJ(long value);

        @SidekarField
        public abstract double getD();
        public abstract void setD(double value);

        @Override
        public String toString() {
            return "Prim["
              + "Z=" + getZ() + ","
              + "B=" + getB() + ","
              + "C=" + getC() + ","
              + "S=" + getS() + ","
              + "I=" + getI() + ","
              + "F=" + getF() + ","
              + "J=" + getJ() + ","
              + "D=" + getD() + "]";
        }
    }
}

